package com.example.baidu.speech.shorts.service.impl;

import com.alibaba.fastjson2.JSON;
import com.example.baidu.speech.shorts.dto.BaiduSpeechShortDTO;
import com.example.baidu.speech.shorts.service.BaiduSpeechShortService;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * 百度语音
 *
 * @author hspcadmin
 */
@Slf4j
@Service
public class BaiduSpeechShortServiceImpl implements BaiduSpeechShortService {

    /**
     * 客户端
     */
    public static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build();

    @Value("${apiKey:clBT9yE6yCusAi1HCxaYLJxI}")
    public String apiKey;
    @Value("${apiKey:YSog1kZxqC8eeBVUstMdlpsrqccYlX5O}")
    public String secretKey;
    /**
     * 用户唯一标识，用来区分用户，计算UV值。建议填写能区分用户的机器 MAC 地址或 IMEI 码，长度为60字符以内。
     */
    @Value("${cuid:J3t7cDAzWAZsc9wxBO5GifzD69EdO8ro}")
    private String cuid;
    /**
     * 百度获取 AccessToken 的URL
     */
    @Value("${baiduAccessTokenUrl:https://aip.baidubce.com/oauth/2.0/token}")
    private String baiduAccessTokenUrl;
    /**
     * 百度短语音识别URL
     */
    @Value("${baiduShortSpeechUrl:https://vop.baidu.com/server_api}")
    private String baiduShortSpeechUrl;

    @Override
    public String getAccessToken() {
        try {
            MediaType mediaType = MediaType.parse("application/json");
            RequestBody body = RequestBody.create(mediaType, "");
            Request request = new Request.Builder()
                    .url(baiduAccessTokenUrl + "?client_id=" + apiKey + "&client_secret=" + secretKey + "&grant_type=client_credentials")
                    .method("POST", body)
                    .addHeader("Content-Type", "application/json")
                    .addHeader("Accept", "application/json")
                    .build();
            Response response = HTTP_CLIENT.newCall(request).execute();

            // response.body() 只能调用一次，调用一次后就关闭了
            JSONObject responseBody = new JSONObject(response.body().string());
            log.info("getAccessToken responseBody[API响应体]：{}", responseBody);

            if (!response.isSuccessful()) {
                log.error("百度AccessToken API响应结果：[{}] - [{}]", responseBody.getString("error"), responseBody.getString("error_description"));
                throw new RuntimeException("[百度语音]获取AccessToken接口调用失败，请检查 API KEY 和 Secret Key 是否配置正确");
            }

            return responseBody.getString("access_token");

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("[百度语音]获取AccessToken失败");
        }
    }

    @Override
    public String recognizingShortSpeechByte(BaiduSpeechShortDTO baiduSpeechShortDTO) {
        if (baiduSpeechShortDTO == null) {
            throw new RuntimeException("请求参数不能为空");
        }
        if (StringUtils.isEmpty(baiduSpeechShortDTO.getFormat())) {
            throw new RuntimeException("语音文件的格式不能为空");
        }

        // 系统自填项 64691938079
        baiduSpeechShortDTO.setRate(16000);
        baiduSpeechShortDTO.setCuid(cuid);
        baiduSpeechShortDTO.setToken(getAccessToken());

        try {
            RequestBody body = RequestBody.create(baiduSpeechShortDTO.getBytes());
            Request request = new Request.Builder()
                    .url(baiduShortSpeechUrl
                            + "?cuid=" + baiduSpeechShortDTO.getCuid()
                            + "&token=" + baiduSpeechShortDTO.getToken()
                    )
                    .method("POST", body)
                    .addHeader("Content-Type", "audio/" + baiduSpeechShortDTO.getFormat() + ";rate=" + baiduSpeechShortDTO.getRate())
                    .build();
            Response response = HTTP_CLIENT.newCall(request).execute();

            // response.body() 只能调用一次，调用一次后就关闭了
            JSONObject responseBody = new JSONObject(response.body().string());
            log.info("recognizingShortSpeechByte responseBody[API响应体]：{}", responseBody);

            if (!response.isSuccessful() || responseBody.getInt("err_no") != 0) {
                log.error("百度短语音识别响应结果：[{}] - [{}]", responseBody.getInt("err_no"), responseBody.getString("err_msg"));
                throw new RuntimeException("[百度语音]短语音识别接口调用失败");
            }

            return responseBody.getJSONArray("result").toString();

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("[百度语音]短语音识别失败");
        }
    }

    @Override
    public String recognizingShortSpeech(BaiduSpeechShortDTO baiduSpeechShortDTO) {
        // 参数校验。BaiduSpeechShortDTO 中每个参数都是必填项，只是有些可以由系统自动赋值
        checkBaiduShortSpeechVO(baiduSpeechShortDTO);

        // 系统自填项 64691938079
        baiduSpeechShortDTO.setRate(16000);
        baiduSpeechShortDTO.setChannel(1);
        baiduSpeechShortDTO.setCuid(cuid);
        baiduSpeechShortDTO.setToken(getAccessToken());

        try {
            MediaType mediaType = MediaType.parse("application/json");
            RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(baiduSpeechShortDTO));
            Request request = new Request.Builder()
                    .url(baiduShortSpeechUrl)
                    .method("POST", body)
                    .addHeader("Content-Type", "application/json")
                    .addHeader("Accept", "application/json")
                    .build();
            Response response = HTTP_CLIENT.newCall(request).execute();

            // response.body() 只能调用一次，调用一次后就关闭了
            JSONObject responseBody = new JSONObject(response.body().string());
            log.info("recognizingShortSpeech responseBody[API响应体]：{}", responseBody);

            if (!response.isSuccessful() || responseBody.getInt("err_no") != 0) {
                log.error("百度短语音识别响应结果：[{}] - [{}]", responseBody.getInt("err_no"), responseBody.getString("err_msg"));
                throw new RuntimeException("[百度语音]短语音识别接口调用失败");
            }

            return responseBody.getJSONArray("result").toString();

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("[百度语音]短语音识别失败");
        }
    }

    /**
     * 参数校验 BaiduSpeechShortDTO
     *
     * @param baiduSpeechShortDTO BaiduSpeechShortDTO对象
     */
    private void checkBaiduShortSpeechVO(BaiduSpeechShortDTO baiduSpeechShortDTO) {
        if (baiduSpeechShortDTO == null) {
            throw new RuntimeException("请求参数不能为空");
        }
        if (StringUtils.isEmpty(baiduSpeechShortDTO.getFormat())) {
            throw new RuntimeException("语音文件的格式不能为空");
        }
        if (StringUtils.isEmpty(baiduSpeechShortDTO.getSpeech())) {
            throw new RuntimeException("本地语音文件的二进制语音数据不能为空");
        }
        if (baiduSpeechShortDTO.getLen() == null || baiduSpeechShortDTO.getLen() <= 0) {
            throw new RuntimeException("本地语音文件的的字节数不能为空");
        }
    }

}
